home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
et
/
et3_0-a1.lha
/
et3
/
src
/
DevBitmap.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-08-26
|
12KB
|
546 lines
#ifdef __GNUG__
#pragma implementation
#endif
#include "DevBitmap.h"
#include "WindowPort.h"
#include "WindowColorMap.h"
#include "Error.h"
#define CACHESIZE 40
struct BitmapCache {
int clock, wcmid;
DevBitmap *org, *dbm;
} Cache[CACHESIZE];
static int cacheclock;
static int lastix;
inline int PaddedBytesPerLine(int w, int depth, u_short pad)
{
return ((w-1)/(pad*8)+1)*depth;
}
//---- DevBitmap ---------------------------------------------------------------
DevBitmap::DevBitmap(Point sz, u_short dep)
{
refcnt= 0;
size= sz;
depth= dep;
cmap= 0;
}
DevBitmap::DevBitmap(DevBitmap *dbm)
{
refcnt= 0;
size= dbm->size;
depth= dbm->depth;
if (dbm->cmap)
cmap= new ColorMap(dbm->cmap);
else
cmap= 0;
}
void DevBitmap::Unref()
{
if (refcnt > 0) {
refcnt--;
if (refcnt == 0)
delete this;
}
}
DevBitmap::~DevBitmap()
{
register BitmapCache *bmp= Cache;
for (int i= 0; i < CACHESIZE; i++, bmp++) {
if (bmp->org == this || bmp->dbm == this) {
DevBitmap *o1= bmp->org, *o2= bmp->dbm;
bmp->org= bmp->dbm= 0;
if (o1)
o1->Unref();
if (o2)
o2->Unref();
bmp->org= 0;
bmp->wcmid= 0;
bmp->clock= 0;
}
}
SafeDelete(cmap);
}
DevBitmap *DevBitmap::DeepClone()
{
DevBitmap *dbm= DevAllocBitmap(size, depth);
dbm->cmap= cmap ? new ColorMap(cmap) : 0;
dbm->DevBitBlt(0, 0, size.x, size.y, TRUE, this, 0, 0);
return dbm;
}
void DevBitmap::DevMapColors(DevBitmap *src, u_long *map)
{
register int x, y;
for (x= 0; x < size.x; x++)
for (y= 0; y < size.y; y++)
SetPixel(x, y, map[src->GetPixel(x, y)]);
}
int DevBitmap::BytesPerLine()
{
return PaddedBytesPerLine(size.x, depth, 1);
}
int DevBitmap::GetColormapSize()
{
if (cmap)
return cmap->Size();
return 0;
}
void DevBitmap::SetColormapSize(int sz)
{
if (cmap == 0)
cmap= new ColorMap(sz);
else
cmap->Expand(sz);
}
RGB DevBitmap::GetColormapEntry(int ix)
{
if (cmap == 0)
cmap= new ColorMap(ix);
return cmap->GetEntry(ix);
}
void DevBitmap::SetColormapEntry(int ix, RGB &rgb)
{
if (cmap == 0)
cmap= new ColorMap(ix);
cmap->SetEntry(ix, rgb);
}
void DevBitmap::ReadData(IStream &is, int bpp, int)
{
int bpl= ((size.x-1)/8+1)*bpp;
byte *bp= new byte[bpl];
int y;
for (y= 0; y < size.y; y++) {
is.read(bp, bpl);
SetRow(y, bp, bpl, bpp);
}
delete bp;
}
void DevBitmap::SetRow(int y, byte *rowdata, int len, int bpp)
{
register u_long v, m;
register int x, i= 0, np, j;
register byte *bp= rowdata;
switch (bpp) {
case 1:
for (x= 0; x < len; x++) {
v= *bp++;
m= 0x80;
for (j= 0; j < 8; j++) {
SetPixel(i++, y, (v & m) ? 1 : 0);
m >>= 1;
}
}
break;
case 4:
for (x= 0; x < len; x++) {
v= *bp++;
SetPixel(i++, y, v >> 4);
SetPixel(i++, y, v & 0xf);
}
break;
case 8:
case 16:
case 24:
case 32:
np= bpp/8;
for (x= 0; x < len/np; x++) {
for (j= 0; j < np; j++)
v= (v << 8) + *bp++;
SetPixel(i++, y, v);
}
break;
}
}
u_long DevBitmap::GetByte(u_int x, u_int y)
{
register u_long b= 0;
register int i;
if (x < 0 || y < 0 || y >= size.y)
return 0;
switch (depth) {
case 1:
x*= 8;
for (i= 0; i < 8; i++) {
b <<= 1;
if (GetPixel(x+i, y))
b|= 1;
}
break;
case 4:
x*= 2;
b= GetPixel(x, y);
b= (b << 4) + GetPixel(x+1, y);
break;
case 8:
b= GetPixel(x, y);
break;
default:
fprintf(stderr, "DevBitmap::GetByte: depth > 8 not yet implemented\n");
break;
}
return b;
}
void DevBitmap::DevBitBlt(int x0, int y0, int w, int h, int op, DevBitmap *s, int sx, int sy)
{
register int x, y;
for (y= 0; y < h; y++) {
for (x= 0; x < w; x++) {
if (op)
SetPixel(x0+x, y0+y, s->GetPixel(sx+x, sy+y));
else
SetPixel(x0+x, y0+y, GetPixel(x0+x, y0+y) | s->GetPixel(sx+x, sy+y));
}
}
}
DevBitmap *DevBitmap::DevScaleBitmap(Point ss)
{
int x= size.x, y= size.y, sx= ss.x, sy= ss.y;
DevBitmap *pr1, *pr2;
register int b, src, dst, d, a1, a2;
float scale;
if (sx == x) // same width
pr1= this;
else if (sx < x) { // x-shrink
pr1= DevAllocBitmap(Point(sx, y), depth);
if (depth > 1) {
scale= (float)x/(float)sx;
for (dst= 0; dst < sx; dst++)
if ((b= (int)(dst*scale+0.5)) < x)
pr1->DevBitBlt(dst, 0, 1, y, TRUE, this, b, 0);
} else {
scale= (float)sx/(float)x;
for (src= 0; src < x; src++)
if ((b= (int)(src*scale+0.5)) < sx)
pr1->DevBitBlt(b, 0, 1, y, FALSE, this, src, 0);
}
} else { // x-magnify
pr1= DevAllocBitmap(Point(sx, y), depth);
d= sx/x;
scale= (float)sx/(float)x;
for (src= 0; src < x; src++) // slice
if ((b= (int)(src*scale+0.5)) < sx)
pr1->DevBitBlt(b, 0, 1, y, TRUE, this, src, 0);
for (src= 0; src < d-1; src++) // smear
pr1->DevBitBlt(src+1, 0, sx-d+1, y, FALSE, pr1, src, 0);
for (a1= src= 0; src < x; src++) { // fill remaining slots
a2= (int)((src+1)*scale+0.5);
if (a1+d != a2)
pr1->DevBitBlt(a2-1, 0, 1, y, TRUE, this, src, 0);
a1= a2;
}
}
if (sy == y) // same height
pr2= pr1;
else if (sy < y) { // y-shrink
pr2= DevAllocBitmap(Point(sx, sy), depth);
if (depth > 1) {
scale= (float)y/(float)sy;
for (dst= 0; dst < sy; dst++)
if ((b= (int)(dst*scale+0.5)) < y)
pr2->DevBitBlt(0, dst, sx, 1, TRUE, pr1, 0, b);
} else {
scale= (float)sy/(float)y;
for (src= 0; src < y; src++)
if ((b= (int)(src*scale+0.5)) < sy)
pr2->DevBitBlt(0, b, sx, 1, FALSE, pr1, 0, src);
}
if (pr1 != this)
delete pr1;
} else if (sy > y) { // y-magnify
pr2= DevAllocBitmap(Point(sx, sy), depth);
d= sy/y;
scale= (float)sy/(float)y;
for (src= 0; src < y; src++) // slice
if ((b= (int)(src*scale+0.5)) < sy)
pr2->DevBitBlt(0, b, sx, 1, TRUE, pr1, 0, src);
for (src= 0; src < d-1; src++) // smear
pr2->DevBitBlt(0, src+1, sx, sy-d+1, FALSE, pr2, 0, src);
for (a1= src= 0; src < y; src++) { // fill remaining slots
a2= (int)((src+1)*scale+0.5);
if (a1+d != a2)
pr2->DevBitBlt(0, a2-1, sx, 1, TRUE, pr1, 0, src);
a1= a2;
}
if (pr1 != this)
delete pr1;
}
return pr2;
}
void DevBitmap::DevHalftone(WindowColorMap *wcm, DevBitmap *spr)
{
register int *next, v, error;
int s= spr->cmap->Size(), *level, *errors, i, x, y, incr, lasterror, *nextbuf;
u_long *out;
RGB result;
level= new int[s];
for (i= 0; i < s; i++)
level[i]= spr->cmap->GetEntry(i).AsGreyLevel();
out= new u_long[256];
errors= new int[256];
for (i= 0; i < 256; i++) {
RGB rgb((short)i);
out[i]= wcm->RGB2Index(&rgb, &result);
errors[i]= i - result.AsGreyLevel();
}
nextbuf= new int[size.x + 4];
next= &nextbuf[2];
for (y= 0; y < size.y; y++) {
if (y & 1) { // scan left
incr= 1;
i= size.x-1;
} else { // scan right
incr= -1;
i= 0;
}
for (lasterror= x= 0; x < size.x; x++, i-= incr) {
v= lasterror + level[spr->GetPixel(i, y)];
if (v < 0)
v= 0;
else if (v > 255)
v= 255;
SetPixel(i, y, out[v]);
error= errors[v];
lasterror= next[i-incr] + (error*7) / 16;
next[i-incr] = error / 16;
next[i] += (error*5) / 16;
next[i+incr]+= (error*3) / 16;
}
}
delete nextbuf;
delete out;
delete errors;
delete level;
}
void DevBitmap::DevFloydSteinberg(WindowColorMap *wcm, DevBitmap *spr)
{
RGB lasterror, error, *nextbuf, *next, rgb, result, v;
register int s= 256, i, x, y, incr;
nextbuf= new RGB[size.x + 4];
next= &nextbuf[2];
for (y= 0; y < size.y; y++) {
if (y & 1) { // scan left
incr= 1;
i= size.x-1;
} else { // scan right
incr= -1;
i= 0;
}
for (x= 0; x < size.x; x++, i-= incr) {
spr->GetRGB(i, y, &rgb);
lasterror+= rgb;
v= lasterror;
v.Clip();
SetPixel(i, y, wcm->RGB2Index(&v, &result));
error= rgb-result;
lasterror= next[i-incr] + (error*7) / 16;
next[i-incr] = error / 16;
next[i] += (error*5) / 16;
next[i+incr]+= (error*3) / 16;
}
}
delete nextbuf;
}
DevBitmap *DevBitmap::FindInCache(WindowColorMap *wcm, Point scale)
{
register int i;
register BitmapCache *bmc;
int wcmid= 0;
if (wcm)
wcmid= wcm->GetId();
cacheclock++;
for (i= 0; i < CACHESIZE; i++) {
bmc= &Cache[(lastix + i) % CACHESIZE];
if (bmc->org == this && scale == bmc->dbm->Size() && wcmid == bmc->wcmid) {
bmc->clock= cacheclock;
return bmc->dbm;
}
}
return 0;
}
void DevBitmap::AddToCache(DevBitmap *dbm, WindowColorMap *wcm)
{
register int i, old= cacheclock;
register BitmapCache *bmc;
for (lastix= i= 0; i < CACHESIZE; i++) {
bmc= &Cache[i];
if (bmc->clock < old) {
old= bmc->clock;
lastix= i;
}
}
bmc= &Cache[lastix];
DevBitmap *o1= bmc->org, *o2= bmc->dbm;
bmc->dbm= bmc->org= 0;
if (o1)
o1->Unref();
if (o2)
o2->Unref();
bmc->dbm= dbm; bmc->dbm->Ref();
bmc->org= this; bmc->org->Ref();
bmc->wcmid= wcm ? wcm->GetId() : 0;
bmc->clock= cacheclock;
}
bool gDither= TRUE;
void DevBitmap::ExpandColors(WindowColorMap *wcm, DevBitmap *dbm, DevBitmap *mask)
{
ColorMap *cm= dbm->cmap;
if (cm) {
if ((cm->IsGrey() || wcm->IsGrey()) && gDither && mask == 0) {
DevHalftone(wcm, dbm);
} else {
register int x, l= cm->Size();
register u_long *map= new u_long[l];
for (x= 0; x < l; x++)
map[x]= wcm->RGB2Index(&cm->map[x]);
if (mask)
map[0]= 0;
DevMapColors(dbm, map);
delete map;
}
} else { // direct color
dbm->SetColormapSize(1 << dbm->depth);
if (gDither && mask == 0) {
DevFloydSteinberg(wcm, dbm);
} else {
RGB rgb;
register int x, y;
for (x= 0; x < size.x; x++)
for (y= 0; y < size.y; y++) {
dbm->GetRGB(x, y, &rgb);
SetPixel(x, y, wcm->RGB2Index(&rgb));
}
}
}
}
void DevBitmap::MapColors(WindowColorMap *wcm, DevBitmap *dbm, DevBitmap *mask)
{
ExpandColors(wcm, dbm, mask);
}
void DevBitmap::ReduceColors(WindowColorMap *wcm, DevBitmap *dbm, DevBitmap *mask)
{
ExpandColors(wcm, dbm, mask);
}
DevBitmap *DevBitmap::PrepareBitmap(WindowPort *port, Point e, DevBitmap *mask)
{
DevBitmap *dbm, *spm;
WindowColorMap *wcm= port->ColorMap();
if (dbm= FindInCache(wcm, e))
return dbm;
dbm= FindInCache(0, e);
if (dbm == 0) {
dbm= DevScaleBitmap(e);
if (cmap && dbm->cmap == 0)
dbm->cmap= new ColorMap(cmap);
AddToCache(dbm, 0);
}
if (cmap == 0 && depth == 1) // no mapping neccessary
return dbm;
int portdepth= port->GetDepth();
spm= DevAllocBitmap(e, portdepth);
if (depth < portdepth) {
spm->ExpandColors(wcm, dbm, mask);
} else if (depth == portdepth) {
spm->MapColors(wcm, dbm, mask);
} else if (depth > portdepth) {
spm->ReduceColors(wcm, dbm, mask);
}
AddToCache(spm, wcm);
return spm;
}
//---- abstract methods --------------------------------------------------------
DevBitmap *DevBitmap::DevAllocBitmap(Point, u_short)
{
AbstractMethod("DevBitmap::DevAllocBitmap");
return 0;
}
void DevBitmap::SetPixel(u_int, u_int, u_long)
{
AbstractMethod("DevBitmap::SetPixel");
}
u_long DevBitmap::GetPixel(u_int, u_int)
{
AbstractMethod("DevBitmap::GetPixel");
return 0;
}
void DevBitmap::SetRGB(u_int, u_int, RGB*)
{
AbstractMethod("DevBitmap::SetRGB");
}
void DevBitmap::GetRGB(u_int, u_int, RGB*)
{
AbstractMethod("DevBitmap::GetRGB");
}